/*
//   Copyright 2008 Dear Soft(http://dear-soft.com)
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
 */

package com.dear.soft.components.properties;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;

import com.dear.soft.components.properties.renderers.RefereceImpl;
import com.dear.soft.components.properties.renderers.ReferenceExpander;
import com.dear.soft.components.properties.renderers.ReferenceName;
import com.dear.soft.components.properties.renderers.ReferenceValue;

public class Category implements Iterable<PropertyDescriptor>,
		Comparable<Category> {
	private final String name;
	private final String description;
	private final CategoryExpander expanderRef;
	private final CategoryValue valueRef;
	private final CategoryName nameRef;
	private final Set<PropertyDescriptor> items;

	private boolean expanded = false;
	private Integer order = 0;

	public Category(String name, String description) {
		super();
		this.items = Collections
				.synchronizedSet(new TreeSet<PropertyDescriptor>());
		this.name = name;
		this.description = description;
		this.expanderRef = new CategoryExpander(this);
		this.valueRef = new CategoryValue(this);
		this.nameRef = new CategoryName(this);
	}

	public String getName() {
		return name;
	}

	public String getDescription() {
		return description;
	}

	public void add(PropertyDescriptor property) {
		items.add(property);
	}

	public void remove(PropertyDescriptor property) {
		items.remove(property);
	}

	public int getSize() {
		return items.size();
	}

	public void expand() {
		this.expanded = true;
	}

	public void collapse() {
		this.expanded = false;
	}

	public void swapFolding() {
		if (isExpanded()) {
			collapse();
		} else {
			expand();
		}
	}

	public boolean isExpanded() {
		return this.expanded;
	}

	public static class CategoryExpander extends RefereceImpl<Category>
			implements ReferenceExpander<Category> {
		public CategoryExpander(Category ref) {
			super(ref);
		}
	}

	public static class CategoryName extends RefereceImpl<Category> implements
			ReferenceName<Category> {
		public CategoryName(Category ref) {
			super(ref);
		}
	}

	public static class CategoryValue extends RefereceImpl<Category> implements
			ReferenceValue<Category> {
		public CategoryValue(Category ref) {
			super(ref);
		}
	}

	public CategoryExpander getExpanderRef() {
		return expanderRef;
	}

	public CategoryValue getValueRef() {
		return valueRef;
	}

	public CategoryName getNameRef() {
		return nameRef;
	}

	public Iterator<PropertyDescriptor> iterator() {
		if (isExpanded()) {
			return items.iterator();
		}
		return new ArrayList<PropertyDescriptor>().iterator();
	}

	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result
				+ ((description == null) ? 0 : description.hashCode());
		result = prime * result + ((items == null) ? 0 : items.hashCode());
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		final Category other = (Category) obj;
		if (description == null) {
			if (other.description != null)
				return false;
		} else if (!description.equals(other.description))
			return false;
		if (items == null) {
			if (other.items != null)
				return false;
		} else if (!items.equals(other.items))
			return false;
		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;

		return true;
	}

	public int getOrder() {
		return order;
	}

	public void setOrder(int order) {
		this.order = order;
	}

	@Override
	public int compareTo(Category o) {
		int res = order.compareTo(o.getOrder());
		if (res == 0) {
			new Integer(hashCode()).compareTo(o.hashCode());
		}
		return res;
	}

	public Set<PropertyDescriptor> getItems() {
		return items;
	}

}
